package pogvue.gui;

import pogvue.gui.schemes.*;

import pogvue.io.*;
import pogvue.gui.hub.*;
import pogvue.analysis.*;
import pogvue.datamodel.*;
import pogvue.gui.event.AlignViewportEvent;
import pogvue.gui.event.AlignViewportListener;
import pogvue.gui.event.FontChangeEvent;
import pogvue.gui.schemes.ColourSchemeI;

import java.awt.*;
import java.util.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;

public class SeqCanvas extends ControlledCanvas implements AlignViewportListener,
						ActionListener,
						MouseMotionListener,
						MouseListener,
						KeyListener {


  Hashtable mats;

    public JFrame logoFrame;
  public SequenceFetchThread sft;
  public SearchThread        st;

  public int mousepos;
  public int lastres;
  public int lastseq;

  public boolean mouseDown;
  public  Graphics          gg;
  
  private Image             img;
  private int               imgWidth;
  private int               imgHeight;
  
  public boolean    buffer = true;
  
  private final AlignViewport     av;
  
  final int pady = 2;
  
  private int oldstartx;
  private int oldstarty;
  private int oldendx;
  private int oldendy;
  
  private boolean paintFlag = false;
  
  private int chunkHeight;
  private int chunkWidth;
  
  private final FeatureRenderer          fr  = new FeatureRenderer();
  //private final BlockRenderer            br  = new BlockRenderer();
  private final ConsBlockRenderer        cbr = new ConsBlockRenderer();
  private final ConservedCpGRenderer     cgr = new ConservedCpGRenderer();
  private final InsertRenderer           ir  = new InsertRenderer();
  private final InsertDensityRenderer    ir2 = new InsertDensityRenderer();
  private final ExonScoreRenderer        es  = new ExonScoreRenderer();
  private final TotalExonScoreRenderer   te  = new TotalExonScoreRenderer();
  private final WobbleExonScoreRenderer  we  = new WobbleExonScoreRenderer();
  private final WobbleSelectionExonScoreRenderer        wse = new WobbleSelectionExonScoreRenderer();
  private final CpGRenderer              cg  = new CpGRenderer();
  private final LogoRenderer             lr  = new LogoRenderer();
  private final GCRenderer               gc  = new GCRenderer();
  private final LogLikeRenderer          ll  = new LogLikeRenderer();
  private final TranslationRenderer      tr  = new TranslationRenderer();
  private final ReverseTranslationRenderer  rtr = new ReverseTranslationRenderer();
  private final GFFBaseRenderer          gf  = new GFFBaseRenderer();
  private final GraphBaseRenderer          gr  = new GraphBaseRenderer();
  private final PercentIdentityRenderer  pr  = new PercentIdentityRenderer();
  private final ConsensusRenderer        cr  = new ConsensusRenderer();
  private final BaseRenderer             br = new BaseRenderer();
  public SeqCanvas(AlignViewport av,Controller c) {
    this.av         = av;
    
    addKeyListener(this);
    addMouseMotionListener(this);
    addMouseListener(this);
    setController(c);
    
  }
  public boolean handleAlignViewportEvent(AlignViewportEvent e) {

    if (e.getAlignViewport() == av) {

      paintFlag = e.getType() == AlignViewportEvent.COLOURING ||
	e.getType() == AlignViewportEvent.DELETE ||
	e.getType() == AlignViewportEvent.ORDER ||
	e.getType() == AlignViewportEvent.SHOW ||
	e.getType() == AlignViewportEvent.WRAP;
      
      if (e.getType() == AlignViewportEvent.RESHAPE ||
	  e.getType() == AlignViewportEvent.COLOURING) {
	   paintFlag = true;
      }

      paintComponent(this.getGraphics());
    } else {
      // System.out.println("Non matching viewport");
    }
      return true;
  }
  
  private void drawScale(Graphics g,int startx, int endx,double charWidth, int charHeight,int ypos) {
    int scalestartx = startx - startx%10 + 10;
    
    gg.setColor(Color.black);
    
    for (int i=scalestartx;i < endx;i+= 10) {
      String string = String.valueOf(i);
      gg.drawString(string,(int)((i-startx-1)*charWidth),ypos+15 - charHeight*(2));
    }
  }
  
  
  /**
   * Definitions of startx and endx (hopefully):
   * SMJS This is what I'm working towards!
   *   startx is the first residue (starting at 0) to display.
   *   endx   is the last residue to display (starting at 0).
   *   starty is the first sequence to display (starting at 0).
   *   endy   is the last sequence to display (starting at 0).
   * NOTE 1: The av limits are set in setFont in this class and
   * in the adjustment listener in SeqPanel when the scrollbars move.
   */
  
  public void paintComponent(Graphics g) {

    System.out.println("NowRes " + av.getStartRes() + "\t" + av.getEndRes());
    System.out.println("OldRes " + oldstartx + "\t" + oldendx);
    AlignmentI da = av.getAlignment();
    
    if (img == null ||
	imgWidth  != size().width  ||
	imgHeight != size().height ||
	paintFlag == true||
	buffer == false) {
	
	//System.out.println("Reset canvas " + img + " " + imgWidth + " " + size().width + " " + paintFlag);

      imgWidth  = (size().width > 0 ? size().width : 1);
      imgHeight = (size().height > 0 ? size().height : 1);
      
      img = createImage(imgWidth,imgHeight);
      gg  = img.getGraphics();
      
      
      // SMJS I added this in to update the AV when the size changes
      //      until I figure out how this should be done
      setFont(av.getFont());
      
      gg.setFont(av.getFont());
      
      paintFlag = false;
      
      oldstartx = -1;
      oldendx   = -1;
      oldstarty = -1;
      oldendy   = -1;
    }
    
    if (buffer == false) {
      gg = g;
    }

    int startx = av.getStartRes();
    int starty = av.getStartSeq();
    
    int endx   = av.getEndRes();
    int endy   = av.getEndSeq();
    
    double charWidth  = av.getCharWidth();
    int charHeight    = av.getCharHeight();
    
    chunkWidth = (int)(size().width/charWidth);
    chunkHeight =  (da.getHeight() + 2)*charHeight;
    
    av.setChunkHeight(chunkHeight);
    av.setChunkWidth(chunkWidth);
    
    int offy = av.getStartSeq();

    if (oldendx == -1) {
      
      fillBackground(gg,Color.white,0,0,size().width,size().height);
      
      drawPanel(gg,startx,endx,starty,endy,startx,starty,0);
        
      oldstartx = startx;
      oldendx   = endx;
      oldstarty = starty;
      oldendy   = endy;
        
    }  else if (oldstartx < startx) {
      // This is dragging horizontal scrollbar to the right
      
      int delx  = (int)((startx - oldstartx) * charWidth);
      int delx2 = (int)((oldendx - startx + 1)   * charWidth);
      
      System.out.println("Moving is " + (startx-oldstartx));
      
      gg.copyArea(delx,0,delx2,AlignmentUtil.getPixelHeight(starty,endy,charHeight),-delx,0);
      
      if (startx > oldendx) {
        drawPanel(gg,startx,endx,starty,endy,startx,starty,0);
      } else {
        drawPanel(gg,oldendx+1,endx,starty,endy,startx,starty,0);
      }
      
      oldstartx = startx;
      oldendx   = endx;
      
    } else if (oldstartx > startx) {
      
      int delx  = (int)((oldstartx - startx) * charWidth);
      int delx2 = (int)((endx - oldstartx + 1)   * charWidth);
      
      gg.copyArea(0,0,delx2,AlignmentUtil.getPixelHeight(starty,endy,charHeight),delx,0);
      
      if (oldstartx > endx) {
        drawPanel(gg,startx,endx,starty,endy,startx,starty,0);
      } else {
        drawPanel(gg,startx,oldstartx-1,starty,endy,startx,starty,0);
      }
      
      oldstartx = startx;
      oldendx   = endx;
      
    }  else if (oldstarty < starty) {
      
      int dely  = AlignmentUtil.getPixelHeight(oldstarty,starty,charHeight);
      int dely2 = AlignmentUtil.getPixelHeight(starty,oldendy,charHeight);
      
      gg.copyArea(0,dely,(int)((endx-startx)*charWidth),dely2,0,-dely);
      
      if (starty > oldendy) {
        drawPanel(gg,startx,endx,starty,endy,startx,starty,0);
      } else {
        drawPanel(gg,startx,endx,oldendy,endy,startx,starty,0);
      }
      
      oldstarty = starty;
      oldendy   = endy;
      
    } else if (oldstarty > starty) {
      
      int dely  = AlignmentUtil.getPixelHeight(endy,oldendy,charHeight);
      int dely2 = AlignmentUtil.getPixelHeight(oldstarty,endy,charHeight);
      
      gg.copyArea(0,0,(int)((endx-startx)*charWidth),dely2,0,dely);
      
      if (oldstarty > endy) {
        drawPanel(gg,startx,endx,starty,endy,startx,starty,0);
      } else {
        drawPanel(gg,startx,endx,starty,oldstarty,startx,starty,0);
      }
      
      oldstarty = starty;
      oldendy   = endy;
    }
    
    if ((oldendy -oldstarty) > (size().width / av.getCharWidth())) {
      System.out.println("LIMITS ERROR LIMITS ERROR");
      System.out.println("Corrds " + (oldendy-oldstarty) + " " + size().width/av.getCharWidth() + " " + size().width + " " + av.getCharWidth());
    }

    if (buffer) {
      
      g.drawImage(img,0,0,this);

    } else {
      System.out.println("Getting graphics");
      gg = img.getGraphics();
      buffer = true;
    }
    
    
  }
  
  private void tidyEdges(Graphics g) {
    int sidex  = (int)(size().width / (av.getCharWidth() * av.getCharWidth()));
    int boty   = size().height / av.getCharHeight() * av.getCharHeight();
    
    fillBackground(g,
            Color.white,
            0,boty,size().width,size().height - boty);
    fillBackground(g,
            Color.white,
            sidex,0,size().width-sidex,size().height);
  }
  
  
  
  public void drawPanel(Graphics g,int x1,int x2, int y1, int y2,int startx, int starty,int offset) {

    
    //System.out.println("drawPanel called with g      = " + g);
    //System.out.println("                      x1     = " + x1);
    //System.out.println("                      x2     = " + x2);
    //System.out.println("                      y1     = " + y1);
    //System.out.println("                      y2     = " + y2);
    //System.out.println("                      startx = " + startx);
    //System.out.println("                      starty = " + starty);
    
    
    g.setFont(av.getFont());
    
    AlignmentI        da         = av.getAlignment();
    double            charWidth  = av.getCharWidth();
    int               charHeight = av.getCharHeight();
    
    Vector    pid    = null;
    int[][]  intpid  = null;
    Hashtable blocks = null;
    
    RendererI sr = av.getRenderer();
    
    Vector tmpseq = new Vector();
    Vector hide = av.hiddenSequences();    

    if (av.getVisibleSequence() == true) {
      if (av.getAlignment().getSequenceAt(0).getSequence(x1,x2).indexOf("X") >= 0) {

	getSequence();
      }

    } else {
          for (int i = 0; i < av.getAlignment().getHeight(); i++) {
	    SequenceI s = av.getAlignment().getSequenceAt(i);
	    if (!hide.contains(s) && s.getSequence().length() > 0) {
	      hide.addElement(s);
	    }
	  }
    }

    for (int i = 0; i < av.getAlignment().getHeight(); i++) {
      SequenceI s = av.getAlignment().getSequenceAt(i);

      if (!av.getSelection().contains(s) && !hide.contains(s)) {
	
	  tmpseq.addElement(s);
      }
    }

    //System.out.println("Here after height loop " + sr);    
    if ((sr instanceof SequenceRenderer ||
	sr instanceof ConsensusRenderer ||
	sr instanceof ConflateAlignRenderer ||
	sr instanceof KmerFrequencyRenderer) &&
	av.getVisibleSequence() == true) {
      //pid    = AAFrequency.calculate(tmpseq,0,av.getAlignment().getHeight()-1);
      //System.out.println("Calculating pid");

      pid    = AAFrequency.calculate(av.getAlignment().getSequences(),x1,x2);
      
    } else if (sr instanceof GraphRenderer && av.getVisibleSequence() == true) {

      //System.out.println("Calculating intpid");

      intpid = AAFrequency.calculatePID_test(av.getAlignment().getSequenceAt(0),
					     av.getAlignment().getSequences(),
					     av.getPIDWindow(),x1,x2);

      
    } else if (sr instanceof WobbleExonScoreRenderer && av.getVisibleSequence() == true) {
      int window = av.getPIDWindow();
      
      window = window /3;
      
      if (window == 0) {
        window = 1;
      }
      //System.out.println("Calculating frame pid");
      pid = AAFrequency.calculateFrameBasedPID(av.getAlignment().getSequenceAt(0),
              av.getAlignment().getSequences(),
              window,x1,x2);
    }
    
    //System.out.println("Here after renderers");    
    //System.out.println("Y " + starty + " " + y2 + " " + av.getEndSeq() +  " " + y1);
    
    if (y2 > starty && y1 < av.getEndSeq()) {
      
	fillBackground(g,
		       Color.white,
		       (int)((x1-startx)*charWidth),
		       offset + AlignmentUtil.getPixelHeight(starty,y1,av.getCharHeight()),
		       (int)((x2-x1+1)*charWidth),
		       offset + AlignmentUtil.getPixelHeight(y1,y2,av.getCharHeight()));
	
	//System.out.println("Size " + tmpseq.size());

     for (int i = 0; i < tmpseq.size(); i++) {
        RendererI r = sr;
     
	SequenceI seq = (SequenceI)tmpseq.elementAt(i);//av.getAlignment().getSequenceAt(i);

        if (seq instanceof GFF) {
	    GFF gff = (GFF)seq;
	    if (gff.getScores() == null) {
		//System.out.println("Renderer " + gf + " " + av.getAlignment().getSequenceAt(i));
	      r = gf;
	    } else {
			r = gr;
	//		r = plr;
	    }
        } else if ( i == 0) {
          r = av.getRenderer();
        } else if (seq.getName().indexOf("Logo") == 0) {
          r = lr;
        } else if (seq.getName().indexOf("CpG") == 0) {
          r = cg;
        } else if (seq.getName().indexOf("InsertDens") == 0) {
          r = ir2;
        } else if (seq.getName().indexOf("Insert") == 0) {
          r = ir;
        } else if (seq.getName().indexOf("GC") == 0) {
          r = gc;
        } else if (seq.getName().indexOf("GFF") == 0) {
          r = fr;
        } else if (seq.getName().indexOf("Exon") == 0) {
          r = es;
        } else if (seq.getName().indexOf("WobbleExon") == 0) {
          
          int window = av.getPIDWindow();
          
          window = window /3;
          
          if (window == 0) {
            window = 1;
          }
          
          pid = AAFrequency.calculateFrameBasedPID(av.getAlignment().getSequenceAt(0),
                  av.getSelection().asVector(),
                  window,x1,x2);
          
          r = wse;
        } else if (seq.getName().indexOf("TotalExon") == 0) {
          r = te;
        } else if (seq.getName().indexOf("LL") == 0) {
          r = ll;
        } else if (seq.getName().indexOf("Tran") == 0) {
          r = tr;
        } else if (seq.getName().indexOf("RevTran") == 0) {
          r = rtr;
        }

	if (seq.getName().indexOf("Transfac") == 0) {
	    r = lr;
	}
        
        //System.out.println("Seq " + seq.getName());

        if (r instanceof GraphRenderer && !buffer) {
          ((GraphRenderer)r).os = 1;
        }
        
	//r = br;
	//System.out.println("Drawing " + r);
        r.drawSequence(g,null,seq,
                x1,
                x2,
                (int)((x1-startx)*charWidth),
                offset + AlignmentUtil.getPixelHeight(starty,i,av.getCharHeight()),
                charWidth,
                charHeight,false,av.getShowBoxes(),av.getShowText(),
                pid,
                i,
                av,
                new Hashtable(),
                intpid);
        
        //System.out.println("Done drawing sequence " + i);
        
      }
    }
  }
  
  public static GFF getGFFByName(AlignmentI align,  String name) {

    int i = 0;
    GFF gff = null;
    boolean newSequence = true;
    
    while (i < align.getHeight() && gff == null) {
      if (align.getSequenceAt(i) instanceof GFF &&
	  align.getSequenceAt(i).getName().equals(name)) {
	gff = (GFF)align.getSequenceAt(i);
	newSequence = false;
      }
      i++;
    }

    if (newSequence == true) {
	  gff = new GFF(name,"",1,2);
    }

    return gff;
  }
	

  public void actionPerformed(ActionEvent e) {
    System.out.println("Action performed");

    if (e.getSource() == sft) {
      sft = null;
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.COLOURING));
    }
    if (e.getSource() instanceof  SearchThread) {
      Vector out = st.getOutput();
	
      if (out.size() > 0) {
	GFF gff = getGFFByName(av.getAlignment(),"Transfac");
	
	double thresh = 2;
	
	
	for (int i = 0;i < out.size(); i++) {
	  SequenceFeature sf = (SequenceFeature)out.elementAt(i);
	  if (sf.getScore() >= thresh) {
	    gff.addFeature(sf);
	  }
	  
	}
	
	Vector bumpgff = pogvue.io.GFFFile.bumpGFF(gff);
	
	av.getAlignment().deleteSequence(gff);
	
	GFF top = new GFF("Transfac","",1,2);
	GFF dum = new GFF("Dummy","",1,2);
	
	for (int i = 0 ; i < out.size(); i++) {
	    SequenceFeature sf = (SequenceFeature)out.elementAt(i);
	    if (sf.getScore() >= 20) {
		top.addFeature(sf);
	    }
	}
	if (top.getFeatures().size() > 0) {
	    Vector topgff = pogvue.io.GFFFile.bumpGFF(top);
	    for (int i = 0 ; i < topgff.size(); i++) {
		GFF tmpgff = (GFF)topgff.elementAt(i);
		av.getAlignment().addSequence(tmpgff);
	    }
	}

	if (bumpgff.size() > 0) {
	    for (int i = 0 ; i < bumpgff.size(); i++) {
		GFF tmpgff = (GFF)bumpgff.elementAt(i);
		av.getAlignment().addSequence(dum);
		av.getAlignment().addSequence(dum);
		av.getAlignment().addSequence(dum);
		av.getAlignment().addSequence(tmpgff);	    
	    }
	}
	
	
	
	controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.COLOURING));
      }
	st = null;
      
    }
	    

  }
  public void fillBackground(Graphics g,Color c, int x1,int y1,int width,int height) {
    g.setColor(c);
    g.fillRect(x1,y1,width,height);
  }
  
  public int getChunkWidth() {
    return chunkWidth;
  }
  public void update(Graphics g) {
    System.out.println("canvas update");
    paint(g);
  }
  
  public void repaint() {
    // System.out.println("repaint called");
    super.repaint();
  }
  
  public boolean handleFontChangeEvent(FontChangeEvent e) {
    System.out.println("Handling font change");
    setFont(e.getFont());
    //controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    paintFlag = true;
    repaint();
    return true;
  }
  
  public void setFont(int style, int size) {
    setFont(new Font(av.getFont().getName(),style,size));
  }
  
  public void setFont(Font f) {
    //      System.out.println("****** Font " + av);
    
    if (av != null) {
      
      
      if (getGraphics() != null) {
        
        FontMetrics fm = getGraphics().getFontMetrics(f);

        
        int charWidth  = fm.charWidth('W');
        int charHeight = fm.getHeight();
        
        if (f.getSize() > 0 && av.getCharWidth() > 1) {
          av.setCharWidth(charWidth,"SeqCanvas1");
        }
        av.setCharHeight(av.getCharHeight());
        
      } else {
        av.setCharWidth(10,"SeqCanvas2");
        av.setCharHeight(11);
      }
      
      av.setFont(f);
      
      int startres = av.getStartRes();
      int startseq = av.getStartSeq();
      
      // SMJS Was +2
      int endres   = startres + (int)(size().width/av.getCharWidth()-1);
      int endseq   = startseq + size().height/av.getCharHeight();
      
      if (endres > av.getAlignment().getWidth()) {
        endres = av.getAlignment().getWidth();
        
        startres = endres - (int)(size().width/av.getCharWidth());
        endres   = av.getAlignment().getWidth();
        
        if (startres < 0) {
          startres = 0;
        }
      }
      
      if (endseq > av.getAlignment().getHeight()) {
        endseq = av.getAlignment().getHeight();
        startseq = endseq - (int)(size().width/av.getCharWidth());
        
        if (startseq < 0) {
          startseq = 0;
        }
        
      }
      
      av.setStartRes(startres);
      av.setStartSeq(startseq);
      av.setEndRes(endres);
      av.setEndSeq(endseq);
      av.setPixelBounds(getBounds());
      
      //av.setFont(f);
      
      //controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.FONT));
    }
  }

  public boolean isFocusable() {
    return true;
  }

  public void keyTyped(KeyEvent e) {
    //System.out.println("Key typed " + e);
  }

  public void keyPressed(KeyEvent e) {
    //System.out.println("Key pressed " + e);

    char c = e.getKeyChar();

    if (c == 'd') {
      if (av.getCharHeight() > 1) {
	av.setCharHeight(av.getCharHeight()-1);
	controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
      }
    } else if (c == 't') {
	av.setCharHeight(15);
	av.setCharWidth(15,"Text size");
	av.setFont(new Font(av.getFont().getName(),av.getFont().getStyle(),(int)av.getCharHeight()));
	controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'n') {
      // Find feature
      // If gene - get info.
      // Di
    } else if (c == 'p') {
      // Doesn't work
      //av.showGaps(!av.showGaps());
      //System.out.println("Showing gaps " + av.showGaps());
      //controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'x') {
      // hide gappy sequences
      
      int start = av.getStartRes();
      int end   = av.getEndRes();

      for (int i = 0; i < av.getAlignment().getHeight(); i++) {
	Sequence seq = (Sequence)av.getAlignment().getSequenceAt(i);

	if (seq.getSequence().length() > 0) {
	  int count = 0;
	  int j = start;
	  while (j <= end) {
	    if (seq.getSequence().substring(j,j+1).equals("-")) {	    

	      count++;
	    }
	    j++;
	  }
	  //System.out.println("Count is " + count + " " + (100*count/(end-start+1) + " " + start + " " + end));
	  if (100*count/(end-start+1) > 30) {
	    av.hideSequence(seq);
	  } else {
	    av.showSequence(seq);
	  }
	}
      }
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'q') {
      // Just a redraw
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'w') {
      av.setPIDWindow(av.getPIDWindow()-1);
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'W') {
      av.setPIDWindow(av.getPIDWindow()+1);
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'b') {
      av.setPIDBaseline(av.getPIDBaseline()-1);
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'B') {
      av.setPIDBaseline(av.getPIDBaseline()+1);
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'r') {
      av.setRenderer(new GraphRenderer());
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'R') {
      av.setRenderer(new ConsensusRenderer());
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'i') {
      av.setCharHeight(av.getCharHeight()+1);
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));

    } else if (c == '-') {

	av.setCharWidth(av.getCharWidth()*0.9,"pog");

	if (av.getCharWidth() >= 6) {
	    
	    av.setFont(new Font(av.getFont().getName(),av.getFont().getStyle(),(int)av.getCharHeight()-3));
	} else {
	    av.setFont(new Font(av.getFont().getName(),av.getFont().getStyle(),0));
	}
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'f') {
	av.setCharWidth((double)5.0,"reset");
	av.setFont(new Font(av.getFont().getName(),av.getFont().getStyle(),(int)av.getCharHeight()));
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == 'c') {
      int seqnum = av.getIndex(mousepos);
      //System.out.println("Sequence is " + seqnum);

      if (seqnum >=0 && seqnum <= av.getAlignment().getHeight()) {
	Sequence seq = (Sequence)av.getAlignment().getSequenceAt(seqnum-1);
	
	String type = seq.getName();
	
	for (int i = 0; i < av.getAlignment().getHeight();i++) {
	  SequenceI tmp = av.getAlignment().getSequenceAt(i);
	  
	  if (tmp.getName().equals(type)) {
	    av.hideSequence(tmp);
	  }
	}
	controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
      }
    } else if (c == 'C') {
      av.hiddenSequences().removeAllElements();

      if (av.getVisibleSequence() == false) {
	for (int i = 0; i <av.getAlignment().getHeight() ; i++) {
	  if (av.getAlignment().getSequenceAt(i).getSequence().length() > 0) {
	    av.hideSequence(av.getAlignment().getSequenceAt(i));
	  }
	}
      }

      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == '1') {
	av.setCharWidth(1,"Set to 1");
	controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == '2') {
	av.setCharWidth(0.5,"Set to 1/2");
	controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    } else if (c == '=') {
      double cw = av.getCharWidth();
      double bpp = 1.0/cw;

      //if (bpp > 1) {
	//av.setCharWidth(1.0/((int)bpp),"pog");
      //} else {
	av.setCharWidth((int)(av.getCharWidth()*1.1),"pog");
	//}
	System.out.println("Setting charWidth");
	if (av.getCharWidth() >= 3) {
	    av.setFont(new Font(av.getFont().getName(),av.getFont().getStyle(),(int)av.getCharWidth()));
	} else {
	    av.setFont(new Font(av.getFont().getName(),av.getFont().getStyle(),0));
	}
	System.out.println("Set font");
	controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
	System.out.println("Sendingevent");
    } else if (c == 's') {
      System.out.println("Pressed s " + av.getVisibleSequence()  + " " + av);

      if (av.getVisibleSequence() == true) {
	System.out.println("hiding sequences "  + av);
	av.setVisibleSequence(false);

	for (int i = 0; i < av.getAlignment().getHeight(); i++) {
	  if (av.getAlignment().getSequenceAt(i).getSequence().length() > 0) {
	    av.hideSequence(av.getAlignment().getSequenceAt(i));
	  }
	}
      } else {
	System.out.println("Showing sequence " + av);
	av.setVisibleSequence(true);
	getSequence();

	Sequence tmp = new Sequence("Logo","",1,1000);
	
	Sequence tmp2 = new Sequence("Dummy","",1,1);
	av.getAlignment().addSequence(tmp2);
	av.getAlignment().addSequence(tmp2);
	av.getAlignment().addSequence(tmp2);
	av.getAlignment().addSequence(tmp);
      }
      controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.RESHAPE));
    }
      
  }

  public void keyReleased(KeyEvent e) {  }

  public void mouseClicked (MouseEvent evt) {

    if (SwingUtilities.isMiddleMouseButton(evt)) {
      System.out.println("Middle Button here!!!\n");
    }

    int x = evt.getX();
    int y = evt.getY();

    //  Get the sequence and the residue

    if (evt.isControlDown() == true) {
      int newres = (int)(x/av.getCharWidth() + av.getStartRes());
      int newseq = av.getIndex(y) -1;
      
      // See if we are overlapping a feature
      
      Sequence seq = (Sequence)av.getAlignment().getSequenceAt(newseq);
      Sequence topseq = (Sequence)av.getAlignment().getSequenceAt(0);

      Vector found = new Vector();      
      if (seq instanceof GFF) {


	Vector features = ((GFF)seq).overlaps(newres,newres);
	
	for (int i = 0; i < features.size(); i++) {
	  SequenceFeature sf = (SequenceFeature)features.elementAt(i);


	  if (sf.getFeatures() != null) {

	    for (int ii = 0; ii < sf.getFeatures().size(); ii++) {
	      
	      SequenceFeature sf2 = (SequenceFeature)(sf.getFeatures().elementAt(ii));

	      if (sf2.getStart() <= newres &&
		  sf2.getEnd() >= newres) {
		System.out.print("Feature\t" + sf2.getFeatures() + "\t" + sf2.getId() + "\t"  + sf2.getType() + "\t" + sf2.getStart() + "\t" + sf2.getEnd() + "\t" + sf2.getScore());
	      

		// If this is a transfac feature display a logo 
		
		if (sf.getHitFeature() != null) {
		
		  System.out.println("\t" + sf2.getHitFeature().getId());
		} else {
		  System.out.println();
		}
		found.addElement(sf2);
	      }
	    }
	  } else {
	    if (sf.getStart() <= newres &&
		sf.getEnd() >= newres) {
		
	      System.out.print("Feature\t" + sf.getId() + "\t"  + sf.getType() + "\t" + sf.getStart() + "\t" + sf.getEnd() + "\t" + sf.getScore());
	      

	      if (sf.getType().equals("Transfac")) {
		String str = topseq.getSequence(sf.getStart(),sf.getEnd());
		
		if (sf.getStrand() == -1) {
		  str = ResidueProperties.reverseComplement(str);
		}

		String matname = sf.getId();

		TFMatrix strmat = LogoPanel.stringToMatrix(str);
		TFMatrix tfmat  = av.getMatrix(matname);
		
		System.out.println("Cons\t" + PwmCluster.getConsensus(strmat.getPwm().getPwm()));
		System.out.println("Cons\t" + PwmCluster.getConsensus(tfmat.getPwm().getPwm()));
		
		LogoPanel lp1 = new LogoPanel(tfmat);
		LogoPanel lp2 = new LogoPanel(strmat);
		
		lp1.setSizeByInfo(true);

		if (logoFrame == null) {
		    logoFrame = new JFrame("Logo test");
		
		    logoFrame.getContentPane().setLayout(new GridLayout(2,1));
		} else {
		    logoFrame.getContentPane().removeAll();
		}
		logoFrame.getContentPane().add(lp1);
		logoFrame.getContentPane().add(lp2);
		
		logoFrame.setSize(450,140);
		logoFrame.setVisible(true);
		
	      }
	      if (sf.getHitFeature() != null) {
		System.out.println("\t" + sf.getHitFeature().getId());
	      } else {
		System.out.println();
	      }
	      found.addElement(sf);
	    }
	  }
	}
      }

      if (found.size() >= 0) {
	for (int i = 0;i < found.size(); i++) {
	  SequenceFeature tmpsf = (SequenceFeature)found.elementAt(i);
	  
	  String seqstr1 = av.getAlignment().getSequenceAt(0).getSequence(tmpsf.getStart()-12,tmpsf.getEnd()+12);


	  if (st == null && ! tmpsf.getType().equals("Transfac")) {
	      System.out.println("Searching " + seqstr1);
	      st = new SearchThread(seqstr1,tmpsf.getStart()-12,this);
	      //	      st.setNames("CTCF_main.15");
	      //st.setNames("NRSF NF-kappa CTCF STAT SRF TATA");
	      st.setViewport(av);
	      st.setThreshold(10);
	      st.start();
	  }
	}
      }
    }
  }


  public void mouseEntered(MouseEvent evt) {  }
  public void mouseExited(MouseEvent evt) { }
  public void mouseMoved(MouseEvent evt) { 
    evt.getComponent().requestFocus();

    mousepos = evt.getY();

    
  }
  public void mouseDragged(MouseEvent e) {
    int x = e.getX();
    int y = e.getY();

    int newres = (int)(x/av.getCharWidth() + av.getStartRes());
    int newseq = av.getIndex(y);

    //System.out.println("X " + x + " " + av.getStartRes());

    if (newres != lastres) {
      int startres = av.getStartRes() - newres + lastres;
      int endres   = av.getEndRes()   - newres + lastres;
      
      //System.out.println("Current pos " + newres + " Previous pos " + lastres + " change start by  " + (newres-lastres));

      if (startres > 0) {
	av.setStartRes(startres);
	av.setEndRes(endres);

	controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.HSCROLL));

      }
    }
    if (newseq != lastseq) {
	int startseq = av.getStartSeq() - newseq + lastseq;
	int endseq = av.getEndSeq() - newseq + lastseq;

      if (startseq > 0) {
	//av.setStartSeq(startseq);
	//av.setEndSeq(endseq);

	//controller.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.HSCROLL));
      }
    }
  }

  public void mousePressed(MouseEvent evt) {
    
    lastres = (int)(evt.getX()/av.getCharWidth() + av.getStartRes());
    lastseq = av.getIndex(evt.getY());
    //System.out.println("Res is " + evt.getX() + " "  + lastres);
  }

  public void mouseReleased(MouseEvent evt) {
  }

  public void getSequence() {
    if (sft == null) {
      sft = new SequenceFetchThread(controller,av);
      sft.setActionListener(this);
      sft.start();
    }
  }
}
